package org.spring.aicloud.controller;

import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import io.minio.errors.*;
import jakarta.annotation.Resource;
import jakarta.servlet.http.HttpServletRequest;
import org.redisson.api.RLock;
import org.redisson.api.RedissonClient;
import org.spring.aicloud.entity.Answer;
import org.spring.aicloud.entity.enums.AIModelEnum;
import org.spring.aicloud.entity.enums.AITypeEnum;
import org.spring.aicloud.service.IAnswerService;
import org.spring.aicloud.utils.AppVariable;
import org.spring.aicloud.utils.MinIoUtil;
import org.spring.aicloud.utils.ResponseEntity;
import org.spring.aicloud.utils.SecurityUtil;
import org.springframework.ai.image.ImagePrompt;
import org.springframework.ai.image.ImageResponse;
import org.springframework.ai.openai.OpenAiChatClient;
import org.springframework.ai.openai.OpenAiImageClient;
//import org.springframework.ai.openai.OpenAiChatModel;
//import org.springframework.ai.openai.OpenAiImageModel;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.util.StringUtils;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

import java.io.ByteArrayInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.net.MalformedURLException;
import java.net.URL;
import java.security.InvalidKeyException;
import java.security.NoSuchAlgorithmException;
import java.util.Base64;
import java.util.List;
import java.util.UUID;
import java.util.concurrent.TimeUnit;

/**
 * @author yexiebao
 * @date 2025/5/4
 */

@RestController
@RequestMapping("/openai")
public class OpenAIController {
    @Resource
    private OpenAiChatClient chatModel;
    @Resource
    private OpenAiImageClient drawModel;
    @Resource
    private IAnswerService answerService;
    @Resource
    private MinIoUtil minIoUtil;
    @Resource
    private RedissonClient redisClient;
    @Resource
    private RedisTemplate<String,Object> redisTemplate;
    /**
     * 调用openai聊天接口
     * @param question
     * @return
     */
    @PostMapping("/chat")
    public ResponseEntity chat(String question) {
        if(!StringUtils.hasLength(question)){
            //输入为空
            return  ResponseEntity.error("请先输入内容");
        }
        long uid  = SecurityUtil.getCurrentUser().getUid();
        String result = "";//大模型返回结果
        boolean saveResult  = false;//数据保存结果
        //分布式锁
        String lockKey = AppVariable.getModelLockKey(uid, AIModelEnum.OPENAI.getCode(), AITypeEnum.CHAT.getCode());
        //1、获取锁
        RLock rLock = redisClient.getLock(lockKey);
        try{
            //2.尝试获取锁
            boolean isLock = rLock.tryLock(AppVariable.LOCK_TIMEOUT, TimeUnit.SECONDS);
            if(!isLock) {
                return ResponseEntity.error("请勿频繁调用接口！");
            }
            // 调用openai接口
            result = chatModel.call(question);
            //结果写入数据库
            Answer answer = new Answer();
            answer.setTitle(question);
            answer.setContent(result);
            answer.setModel(AIModelEnum.OPENAI.getCode());
            answer.setType(AITypeEnum.CHAT.getCode());
            answer.setUid(uid);
            saveResult = answerService.save(answer);
        }catch (Exception e){
        }finally {
            //3.释放锁
            rLock.unlock();
        }

        if(saveResult) {
            return ResponseEntity.ok(result);
        }
        return ResponseEntity.error("保存失败,请重试！");
    }
    /**
     * 调用openai图片接口
     * @param question
     * @return
     */
    @PostMapping("/draw")
    public ResponseEntity draw(String question) throws IOException {
        if(!StringUtils.hasLength(question)){
            //输入为空
            return  ResponseEntity.error("请先输入内容");
        }
        long uid  = SecurityUtil.getCurrentUser().getUid();
        String imgUrl = ""; //minIO图片地址
        boolean saveResult = false; //保存数据库结果
        //使用分布式锁
        String lockKey = AppVariable.getModelLockKey(uid, AIModelEnum.OPENAI.getCode(), AITypeEnum.DRAW.getCode());
        //1.获取分布式锁实例
        RLock rLock = redisClient.getLock(lockKey);
        try {//2.获取分布式锁
            boolean isLock = rLock.tryLock(AppVariable.LOCK_TIMEOUT, TimeUnit.SECONDS);
            if(!isLock){
                return ResponseEntity.error("请勿频繁调用接口！");
            }
            // 调用openai接口
            ImageResponse result = drawModel.call(new ImagePrompt(question));
            String resultUrl = result.getResult().getOutput().getUrl();
            //下载图片,下载URL()指向的图片为 byte[] 或 InputStream
            URL downloadUrl = new URL(resultUrl);

            try( InputStream inputStream =downloadUrl.openStream()){
                imgUrl = minIoUtil.upload("openai-draw-"+ UUID.randomUUID().toString().replace("-", ""), inputStream, "image/png");
            }  catch (ServerException | InsufficientDataException | ErrorResponseException |
                      NoSuchAlgorithmException | InvalidKeyException | InvalidResponseException |
                      XmlParserException | InternalException | IOException e) {
                // 抛出运行时异常
                throw new RuntimeException("上传图片到 MinIO 失败", e);
            }
            Answer answer = new Answer();
            answer.setTitle(question);
            answer.setContent(imgUrl);
            answer.setModel(AIModelEnum.OPENAI.getCode());
            answer.setType(AITypeEnum.DRAW.getCode());
            answer.setUid(uid);
            saveResult = answerService.save(answer);
        }catch (InterruptedException e){
        }finally {
            //3.释放分布式锁
            rLock.unlock();
        }
        if(saveResult) {
            return ResponseEntity.ok(imgUrl);
        }
        return ResponseEntity.error("保存失败,请重试！");
    }

    /**
     * 获取对话历史记录
     * @return
     */
    @RequestMapping("/getchatlist")
    public ResponseEntity getchatlist() {
        Long uid = SecurityUtil.getCurrentUser().getUid();
        String cacheKey = AppVariable.getListCacheKey(uid,AIModelEnum.OPENAI.getCode(),AITypeEnum.CHAT.getCode());
        System.out.println("缓存键名"+cacheKey);
        Object cacheList = redisTemplate.opsForValue().get(cacheKey);
        if(cacheList==null){//缓存不存在
            System.out.println("openai未触发redis缓存！");
            //条件查询
            QueryWrapper<Answer> queryWrapper = new QueryWrapper<>();
            queryWrapper.eq("uid",uid);
            queryWrapper.eq("type", AITypeEnum.CHAT.getCode());
            queryWrapper.eq("model",AIModelEnum.OPENAI.getCode());
            queryWrapper.orderByDesc("aid");
            List<Answer> list = answerService.list(queryWrapper);
            //存储到redis中
            redisTemplate.opsForValue().set(cacheKey,list,1,TimeUnit.DAYS);
            return ResponseEntity.ok(list);
        }else{
            System.out.println("openai触发了redis缓存！");
            return ResponseEntity.ok(cacheList);
        }
    }

    /**
     * 获取画图历史记录
     * @return
     */
    @RequestMapping("/getdrawlist")
    public ResponseEntity getdrawlist() {
        //条件查询
        Long uid = SecurityUtil.getCurrentUser().getUid();
        QueryWrapper<Answer>queryWrapper = new QueryWrapper<>();
        queryWrapper.eq("uid",uid);
        queryWrapper.eq("type",AITypeEnum.DRAW.getCode());
        queryWrapper.eq("model",AIModelEnum.OPENAI.getCode());
        queryWrapper.orderByDesc("aid");
        //查询数据库
        return ResponseEntity.ok(answerService.list(queryWrapper));
    }

}